#include "stdafx.h"
#include "FolderDlg.h"
#include "Dlgs.h"
#include "commctrl.h"
#include "shobjidl.h"

CFolderDlg::CFolderDlg(LPCTSTR lpszInitPath)
{
	m_hShell32 = NULL;
	m_wndProc = NULL;
	memset(m_sPath, 0, sizeof(m_sPath));
	if(lpszInitPath != NULL)
		_tcscpy_s(m_szInitPath, MAX_PATH, lpszInitPath);
	else
		memset(m_szInitPath, 0, sizeof(m_szInitPath));
}

CFolderDlg::~CFolderDlg(void)
{
	if(m_hShell32 != NULL)
		FreeLibrary(m_hShell32);
	m_hShell32 = NULL;
}


LRESULT CALLBACK WindowProcNew(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	CFolderDlg* pThis = (CFolderDlg*)GetWindowLong(hwnd, GWL_USERDATA);
	if(pThis == NULL)
		return -1;

	if(message == WM_COMMAND && HIWORD(wParam) == BN_CLICKED)
	{
		if(LOWORD(wParam) == IDOK)
		{
			::SendMessage(hwnd, CDM_GETFILEPATH, MAX_PATH, (LPARAM)pThis->m_sPath);
			HWND cmb13Wnd = GetDlgItem(hwnd, cmb13);

			TCHAR szTitle[MAX_PATH] = {0};
			::GetWindowText(cmb13Wnd, szTitle, MAX_PATH);
			TCHAR* szFileName = PathFindFileName(pThis->m_sPath);
			if(_tcsicmp(szTitle, szFileName) != 0)
			{
				PathRemoveFileSpec(pThis->m_sPath);
				PathAppend(pThis->m_sPath, szTitle);
			}

			if(PathIsDirectory(pThis->m_sPath))
			{
				EndDialog(hwnd, IDOK);
			}
			else
			{
				TCHAR szMsg[2048] = {0};
				_stprintf_s(szMsg, 2048, _T("%s doesn't exist!\r\nPlease choose again!"), pThis->m_sPath);
				::MessageBox(hwnd, szMsg, _T("Warning"), MB_OK | MB_ICONWARNING);
			}
			return 0;
		}
	}
	return CallWindowProc(pThis->m_wndProc, hwnd, message, wParam, lParam);
}

UINT_PTR CALLBACK FolderHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
	if(uiMsg == WM_NOTIFY)
	{
		LPNMHDR hdr = (LPNMHDR)lParam;
		if(hdr->code == CDN_INITDONE)
		{
			LPOFNOTIFY lpofn = (LPOFNOTIFY)lParam;
			CFolderDlg* pThis = (CFolderDlg*)lpofn->lpOFN->lCustData;

			HWND hParent = GetParent(hdlg);
			::SendMessage(hParent, CDM_HIDECONTROL, stc2, 0);
			::SendMessage(hParent, CDM_HIDECONTROL, cmb1, 0);
			::SendMessage(hParent, CDM_HIDECONTROL, edt1, 0);
			::SendMessage(hParent, CDM_HIDECONTROL, chx1, 0);

			::SendMessage(hParent, CDM_SETCONTROLTEXT, stc3, (LPARAM)_T("Folder Name:"));
			RECT rcWnd = {0};
			GetWindowRect(hParent, &rcWnd);
			rcWnd.bottom -= 30;
			SetWindowPos(hParent, NULL, 0, 0, rcWnd.right - rcWnd.left, rcWnd.bottom - rcWnd.top, SWP_NOMOVE | SWP_NOZORDER);

			SetWindowLong(hParent, GWL_USERDATA, (long)lpofn->lpOFN->lCustData);
			pThis->m_wndProc = (WNDPROC)SetWindowLongPtr(hParent, GWLP_WNDPROC, (LPARAM)WindowProcNew);
		}
		else if(hdr->code == CDN_SELCHANGE)
		{
			LPOFNOTIFY lpofn = (LPOFNOTIFY)lParam;
			CFolderDlg* pThis = (CFolderDlg*)lpofn->lpOFN->lCustData;
			HWND hParent = GetParent(hdlg);
			SendMessage(hParent, CDM_GETFILEPATH, MAX_PATH, (LPARAM)pThis->m_sPath);
			TCHAR* pFolderName = PathFindFileName(pThis->m_sPath);

			::SendMessage(hParent, CDM_SETCONTROLTEXT, edt1, (LPARAM)pFolderName);
		}
		else if(CDN_FOLDERCHANGE == hdr->code)
		{
			LPOFNOTIFY lpofn = (LPOFNOTIFY)lParam;
			CFolderDlg* pThis = (CFolderDlg*)lpofn->lpOFN->lCustData;
			HWND hParent = GetParent(hdlg);
			::SendMessage(hParent, CDM_SETCONTROLTEXT, edt1, (LPARAM)_T(""));
		}
	}
	return NULL;
}

int CFolderDlg::DoModal(HWND hParent)
{
	int nRet = DoModalEx(hParent);
	if(nRet > 0)
		return nRet;

	TCHAR szFile[MAX_PATH] = {0};
	OPENFILENAME ofn = {0};
	ofn.lStructSize = sizeof(ofn);
	ofn.lpstrFilter = _T("Folders Only\0zzzzzzzzz.zzzzzzzzzzzzzzzzzzzzzz\0");
	ofn.Flags = OFN_ENABLEHOOK | OFN_EXPLORER | OFN_FILEMUSTEXIST;
	ofn.hwndOwner = hParent;
	ofn.lpfnHook = FolderHookProc;

	ofn.lpstrFile = szFile;
	ofn.nMaxFile = sizeof(szFile);
	ofn.nFilterIndex = 1;
	ofn.lpstrFileTitle = NULL;
	ofn.nMaxFileTitle = 0;
	ofn.lCustData = (LPARAM)this;
	ofn.lpstrInitialDir = m_szInitPath;


	BOOL bRet = GetOpenFileName(&ofn);
	if(bRet && m_sPath[0] != _T('\0'))
		return IDOK;

//	DWORD dwErr = CommDlgExtendedError();
	return IDCANCEL;
}


typedef HRESULT (STDAPICALLTYPE *SHCreateItemFromParsingNamePtr)(PCWSTR , IBindCtx*, REFIID , void **);

int CFolderDlg::DoModalEx(HWND hParent)
{
	CComPtr<IFileOpenDialog> dialog;
	HRESULT hr = dialog.CoCreateInstance(__uuidof(FileOpenDialog));
	if(FAILED(hr) || dialog == NULL)
		return -1;

	CComPtr<IShellItem> shellItem;
	m_hShell32 = LoadLibrary(_T("shell32.dll"));
	if(m_hShell32 == NULL)
		return -1;

	if(m_szInitPath[0] != _T('\0'))
	{
		SHCreateItemFromParsingNamePtr pfn = NULL;
		pfn = (SHCreateItemFromParsingNamePtr)GetProcAddress(m_hShell32, "SHCreateItemFromParsingName");
		hr = pfn(m_szInitPath, 0, IID_IShellItem, reinterpret_cast<void**>(&shellItem));
		dialog->SetFolder(shellItem);
	}
	dialog->SetOptions(FOS_PICKFOLDERS);
	hr = dialog->Show(hParent);
	if(S_OK == hr)
	{
		CComPtr<IShellItem> itemResult;
		hr = dialog->GetResult(&itemResult);

		WCHAR* buffer = NULL;
		hr = itemResult->GetDisplayName(SIGDN_FILESYSPATH, &buffer);
		if(SUCCEEDED(hr) && buffer != NULL)
		{
			_tcscpy_s(m_sPath, MAX_PATH, buffer);
			CoTaskMemFree(buffer);
		}
		return IDOK;
	}

	return IDCANCEL;
}
